﻿/******************************************************************************
* SunnyUI.FrameDecoder 开源TCP、串口数据解码库。
* CopyRight (C) 2022-2023 ShenYongHua(沈永华).
* QQ群：56829229 QQ：17612584 EMail：SunnyUI@qq.com
*
* Blog:   https://www.cnblogs.com/yhuse
* Gitee:  https://gitee.com/yhuse/SunnyUI.FrameDecoder
*
* SunnyUI.FrameDecoder.dll can be used for free under the MIT license.
* If you use this code, please keep this note.
* 如果您使用此代码，请保留此说明。
******************************************************************************
* 文件名称: BaseByteFrameDecoder.cs
* 文件说明: 字节帧解码器基类
* 当前版本: V1.0
* 创建日期: 2022-11-01
*
* 2022-11-01: V1.0.0 增加文件说明
******************************************************************************/

using System;
using System.Threading.Tasks;

namespace Sunny.FrameDecoder
{
    /// <summary>
    /// 字节帧解码器基类
    /// </summary>
    public abstract class BaseByteFrameDecoder : BaseFrameDecoder, IByteFrameDecoderCloneable
    {
        /// <summary>
        /// 数据缓存
        /// </summary>
        protected readonly DataCache<byte> Cache = new();

        /// <summary>
        /// 数据类型
        /// </summary>
        public sealed override FrameDataType DataType => FrameDataType.HEX;

        /// <summary>
        /// 释放对象
        /// </summary>
        /// <param name="disposing">ture时一般位主动调用释放，false一般为GC调用析构函数时释放</param>
        protected override void Dispose(bool disposing)
        {
            if (!IsDisposed && disposing)
            {
                IsDisposed = true;

                //释放资源
                Cache.Dispose();
            }
        }

        /// <summary>
        /// 生成当前解码器副本
        /// </summary>
        /// <returns></returns>
        public abstract BaseByteFrameDecoder Clone();

        /// <summary>
        /// 返回解码结果
        /// </summary>
        /// <param name="start">起始位置</param>
        /// <param name="length">长度</param>
        /// <returns></returns>
        public byte[] GetResult(int start, int length)
        {
            byte[] result = new byte[length];
            Cache.WrittenSpan.Slice(start, length).CopyTo(result.AsSpan());
            return result;
        }

        /// <summary>
        /// 解码
        /// </summary>
        /// <param name="data">输入数据</param>
        public void Decode(ReadOnlySpan<byte> data)
        {
            CheckTimeout();
            if (data.Length == 0) return;
            if (!PrepareDecode(data)) return;
            if (Cache.WrittenCount + data.Length >= CacheMaxSize) Reset();
            Cache.Add(data);
            if (Cache.WrittenCount < FrameExceptDataLength) return;
            Decoding();
            FinishDecode();
            DoAfterDecoder(this);
        }

        /// <summary>
        /// 异步解码
        /// </summary>
        /// <param name="data">输入数据</param>
        /// <returns></returns>
        public async Task DecodeAsync(ReadOnlyMemory<byte> data)
        {
            CheckTimeout();
            if (data.Length == 0) return;
            if (!PrepareDecode(data.Span)) return;
            if (Cache.WrittenCount + data.Length >= CacheMaxSize) Reset();
            Cache.Add(data.Span);
            if (Cache.WrittenCount < FrameExceptDataLength) return;
            await DecodingAsync();
            FinishDecode();
            DoAfterDecoder(this);
            await Task.CompletedTask.ConfigureAwait(false);
        }

        /// <summary>
        /// 准备数据解码
        /// </summary>
        /// <param name="data">输入数据</param>
        /// <returns>判断此数据是否可以解码</returns>
        protected virtual bool PrepareDecode(ReadOnlySpan<byte> data)
        {
            if (data.Length == 0)
            {
                DecoderError("The data to be decoded is null.", data);
                return false;
            }

            return true;
        }

        /// <summary>
        /// 缓存复位
        /// </summary>
        public override void Reset()
        {
            Cache.Clear();
        }

        /// <summary>
        /// 解码输出事件
        /// </summary>
        public event OnByteFrameArgs OnDecoder;

        /// <summary>
        /// 异步解码输出事件
        /// </summary>
        public event OnByteFrameAsyncArgs OnDecoderAsync;

        /// <summary>
        /// 调用解码输出事件
        /// </summary>
        /// <param name="e"></param>
        protected void InvokeOnDecoder(ByteFrameEventArgs e) => OnDecoder?.Invoke(this, e);

        /// <summary>
        /// 异步调用解码输出事件
        /// </summary>
        /// <param name="e"></param>
        protected async Task InvokeOnDecoderAsync(ByteFrameEventArgs e)
        {
            if (OnDecoderAsync != null)
                await OnDecoderAsync.Invoke(this, e);

            await Task.CompletedTask.ConfigureAwait(false);
        }

        /// <summary>
        /// 解码错误事件
        /// </summary>
        public event OnByteFrameDecoderError OnDecoderError;

        /// <summary>
        /// 解码错误事件
        /// </summary>
        /// <param name="error">错误描述</param>
        /// <param name="data">数据</param>
        protected void DecoderError(string error, ReadOnlySpan<byte> data)
        {
            OnDecoderError?.Invoke(this, new ByteDecoderExceptionEventArgs(error, data.ToArray()));
        }

        /// <summary>
        /// 解析完整帧数据
        /// </summary>
        /// <param name="frame">完整帧数据</param>
        /// <returns>解析是否成功</returns>
        public abstract ByteFrameEventArgs DecodeFrame(ReadOnlySpan<byte> frame);
    }
}
